<template>
  <div
    class="editor-container"
    ref="refEditorContainer"
    :style="{
      width: `${basicPropsValue.width}px`,
      height: `${basicPropsValue.height}px`,
      transform: `scale(${editorContainerScale})`,
      transformOrigin: 'top left'
    }"
  >
    <div
      class="images-container"
      @mousedown="onMouseDown"
      @touchstart="onTouchStart"
      @mousemove="onMouseMove"
      @touchmove="onTouchMove"
      @mouseup="onMouseUp"
      @mouseleave="onMouseUp"
      @touchend="onTouchEnd"
      @touchcancel="onTouchEnd"
    >
      <div
        v-for="(img, i) in editingPreset.images"
        :class="`image-container${i === selectedImageIndex ? ' selected' : ''}`"
        :style="{
          opacity: img.hidden ? '0.3' : '1',
          width: `${img.width}px`,
          height: `${img.height}px`,
          top: `${img.top}px`,
          left: `${img.left}px`,
          transform: `rotate(${img.rotation || 0}deg)`,
          transformOrigin: `${img.originX}% ${img.originY}%`
        }"
        @mousedown="onMouseDownImgItem($event, i)"
        @touchstart="onTouchStartImgItem($event, i)"
      >
        <img :src="getImageUrlFromPath(img.image)" :alt="img.image">
        <div
          class="rotate-btn"
          v-if="img.rotateBtnVisible"
          @mousedown="onMouseDownRotateBtn($event, i)"
          @touchstart="onTouchStartRotateBtn($event, i)"
        ></div>
        <div
          v-if="i === selectedImageIndex"
          class="transform-origin"
          :style="{ top: `${img.originY}%`, left: `${img.originX}%` }"
          @mousedown="onMouseDownTransformOrigin($event, i)"
          @touchstart="onTouchStartTransformOrigin($event, i)"
        ></div>
        <div
          v-if="img.isResizer"
          class="resizer"
          @mousedown="onMouseDownResizer($event, i)"
          @touchstart="onTouchStartResizer($event, i)"
        ></div>
      </div>
    </div>
  </div>
  <div class="prop-editor">
    <div style=" display: inline-block;width: auto;padding: 8px;">
      答案： <a-input-number v-model:value="editingPreset.answer"></a-input-number> 度
    </div>
    <div v-if="selectedImage">
      <div class="prop-item">
        <span class="prop-name">宽度</span>
        <span class="prop-value">
          <a-input-number v-model:value="selectedImage.width"></a-input-number>
        </span>
        <span class="prop-name">高度</span>
        <span class="prop-value">
          <a-input-number v-model:value="selectedImage.height"></a-input-number>
        </span>
      </div>
   
      <div class="prop-item">
        <span class="prop-name">角度</span>
        <span class="prop-value">
          <a-input-number v-model:value="selectedImage.rotation"></a-input-number>
        </span>
      </div>
      <div class="prop-item">
        <span class="prop-name">可拖动</span>
        <span class="prop-value">
          <a-switch v-model:checked="selectedImage.draggable"/>
        </span>
        <span class="prop-name">可重复拖动</span>
        <span class="prop-value">
          <a-switch v-model:checked="selectedImage.infiniteDrag"/>
        </span>
      </div>
      
      <div class="prop-item">
        <!-- <span class="prop-name">可缩放</span>
        <span class="prop-value">
          <a-switch v-model:checked="selectedImage.isResizer"/>
        </span> -->
        <span class="prop-name">等比例缩放</span>
        <span class="prop-value">
          <a-switch v-model:checked="selectedImage.equalProportion"/>
        </span>
      </div>
     
      <!-- <div class="prop-item">
        <a-tooltip>
          <template #title>使用时，可以移动旋转中心</template>
          <span class="prop-name">可移动旋转中心</span>
        </a-tooltip>
        <span class="prop-value">
          <a-switch v-model:checked="selectedImage.canMoveTransformOrigin"/>
        </span>
      </div> -->
     
      <div class="prop-item">
        <span class="prop-name">默认显示旋转按钮</span>
        <span class="prop-value">
          <a-switch v-model:checked="selectedImage.rotateBtnVisible"/>
        </span>
      </div>
      <div class="prop-item" v-show="false">
        <span class="prop-name">旋转角度步长</span>
        <span class="prop-value">
          <a-input-number v-model:value="selectedImage.rotateStep"></a-input-number>
        </span>
      </div>
      <!-- <div class="prop-item">
        <span class="prop-name">旋转中心水平位移</span>
        <span class="prop-value">
          <a-input-number v-model:value="selectedImage.originX"></a-input-number> %
        </span>
      </div>
      <div class="prop-item">
        <span class="prop-name">旋转中心竖直位移</span>
        <span class="prop-value">
          <a-input-number v-model:value="selectedImage.originY"></a-input-number> %
        </span>
      </div> -->
      <!-- <div class="prop-item">
        <a-tooltip>
          <template #title>
            设置分组号后，可通过设置按钮控件的参数属性为此处设置的分组号并将按钮的点击信号绑定到本控件的接口设置分组的显示与隐藏。
            显示某一分组的图片时，其它分组的图片如果没有被拖动过则会被隐藏，未分组的图片不会被隐藏。
          </template>
          <span class="prop-name">分组号</span>
        </a-tooltip>
        <span class="prop-value">
          <a-input v-model:value="selectedImage.group"></a-input>
        </span>
      </div> -->
      <div class="prop-item">
        <span class="prop-name">隐藏</span>
        <span class="prop-value">
          <a-switch v-model:checked="selectedImage.hidden"/>
        </span>
      </div>
      <!-- <div style="padding: 10px;">
        <a-button type="danger" style="width: 100%;" @click="onRemoveImage()">删除图片</a-button>
      </div> -->
    </div>
  </div>

</template>

<script lang="ts">
import {defineComponent, PropType, onMounted, ref, watch, computed} from 'vue';
import type {IImage, IMaterial, IPreset} from './types';

declare global {
  interface Window {
    getEnv: (name: string) => any;
    confirmEdit: () => void;
    cancelEdit: () => void;
  }
}

interface IPointObj2D {
  x: number;
  y: number;
}

interface IMousePos {
  clientX: number;
  clientY: number;
}

interface IMovement2D {
  delta: IPointObj2D;
  from: IMousePos;
  to: IMousePos;
}

export default defineComponent({
  props: {
    basicPropsValue: {
      type: Object as PropType<{ width: number, height: number }>,
      default: () => ({width: 900, height: 600})
    },
    preset: {
      type: Object as PropType<IPreset>, default: () =>({images: [], answer: 0}) 
    },
    materials: {type: Array as PropType<IMaterial[]>, default: () => []},
    onValueUpdated: {type: Function as PropType<(v: IPreset) => void>}
  },
  setup(props) {
    const editingPreset = ref({} as IPreset);

    onMounted(() => {
      if (props.preset) {
        const newPreset = JSON.parse(JSON.stringify(props.preset)) as IPreset;
        newPreset.images.forEach((imgItem) => supplementImageItem(imgItem));
        editingPreset.value = newPreset;
        console.log('editingPreset', editingPreset.value);
        
      }
    });
   
    
    watch(editingPreset, () => {
      if (props.onValueUpdated) {
        props.onValueUpdated(JSON.parse(JSON.stringify(editingPreset.value)));
      }
    }, {deep: true});

    function supplementImageItem(imgItem: IImage) {
      if (typeof imgItem.width === 'undefined') imgItem.width = 100;
      if (typeof imgItem.height === 'undefined') imgItem.height = 100;
      if (typeof imgItem.top === 'undefined') imgItem.top = 0;
      if (typeof imgItem.left === 'undefined') imgItem.left = 0;
      if (typeof imgItem.draggable === 'undefined') imgItem.draggable = false;
      if (typeof imgItem.isResizer === 'undefined') imgItem.isResizer = false;
      if (typeof imgItem.equalProportion === 'undefined') imgItem.equalProportion = false;
      if (typeof imgItem.infiniteDrag === 'undefined') imgItem.infiniteDrag = false;
      if (typeof imgItem.rotatable === 'undefined') imgItem.rotatable = false;
      if (typeof imgItem.rotateBtnVisible === 'undefined') imgItem.rotateBtnVisible = false;
      if (typeof imgItem.rotateStep === 'undefined') imgItem.rotateStep = 15;
      if (typeof imgItem.rotation === 'undefined') imgItem.rotation = 0;
      if (typeof imgItem.originX === 'undefined') imgItem.originX = 50;
      if (typeof imgItem.originY === 'undefined') imgItem.originY = 50;
      if (typeof imgItem.group === 'undefined') imgItem.group = '';
      if (typeof imgItem.hidden === 'undefined') imgItem.hidden = false;
      if (typeof imgItem.canMoveTransformOrigin === 'undefined') imgItem.canMoveTransformOrigin = false;
    }

    function getImageUrlFromPath(imagePath: string) {
      const fullPath = (window.getEnv('fullPath') || '').trim().replace(/\/*$/, '');
      return `${fullPath}/${imagePath}`;
    }

    const selectedImageIndex = ref(-1);
    const selectedImage = computed(() => {
      return editingPreset.value.images?.[selectedImageIndex.value];
    });

    const editorContainerScale = ref(1);

    function calcEditorContainerScale() {
      const widgetWidth = props.basicPropsValue.width || 800;
      const widgetHeight = props.basicPropsValue.height || 600;
      const headerHeight = 40;
      const propPanelWidth = 300;
      const margin = 20;
      const boxWidth = window.innerWidth - propPanelWidth - 2 * margin;
      const boxHeight = window.innerHeight - headerHeight - 2 * margin;
      const widthRatio = boxWidth / widgetWidth;
      const heightRatio = boxHeight / widgetHeight;
      const scale = Math.min(widthRatio, heightRatio);
      return scale;
    }

    window.addEventListener('resize', () => editorContainerScale.value = calcEditorContainerScale());
    onMounted(() => editorContainerScale.value = calcEditorContainerScale());

    const refEditorContainer = ref(null as null | HTMLElement);
    const mousePos = {x: 0, y: 0};
    let editorContainerRect = null as null | DOMRect;

    const resizingImgIndex = ref(-1);

    function onMouseDownResizer(evt: MouseEvent, index: number) {
      evt.preventDefault();
      evt.stopPropagation();
      resizingImgIndex.value = index;
      mousePos.x = evt.clientX;
      mousePos.y = evt.clientY;
    }

    function onTouchStartResizer(evt: TouchEvent, index: number) {
      evt.preventDefault();
      evt.stopPropagation();
      resizingImgIndex.value = index;
      mousePos.x = evt.touches[0].clientX;
      mousePos.y = evt.touches[0].clientY;
    }

    const rotatingImgIndex = ref(-1);

    function onMouseDownRotateBtn(evt: MouseEvent, index: number) {
      evt.preventDefault();
      evt.stopPropagation();
      rotatingImgIndex.value = index;
      mousePos.x = evt.clientX;
      mousePos.y = evt.clientY;
      if (refEditorContainer.value) {
        editorContainerRect = refEditorContainer.value.getBoundingClientRect();
      }
    }

    function onTouchStartRotateBtn(evt: TouchEvent, index: number) {
      evt.preventDefault();
      evt.stopPropagation();
      rotatingImgIndex.value = index;
      mousePos.x = evt.touches[0].clientX;
      mousePos.y = evt.touches[0].clientY;
      if (refEditorContainer.value) {
        editorContainerRect = refEditorContainer.value.getBoundingClientRect();
      }
    }

    const movingTransformOriginImgIndex = ref(-1);

    function onMouseDownTransformOrigin(evt: MouseEvent, index: number) {
      evt.preventDefault();
      evt.stopPropagation();
      movingTransformOriginImgIndex.value = index;
      mousePos.x = evt.clientX;
      mousePos.y = evt.clientY;
    }

    function onTouchStartTransformOrigin(evt: TouchEvent, index: number) {
      evt.preventDefault();
      evt.stopPropagation();
      movingTransformOriginImgIndex.value = index;
      mousePos.x = evt.touches[0].clientX;
      mousePos.y = evt.touches[0].clientY;
    }

    const movingImgIndex = ref(-1);

    function onMouseDownImgItem(evt: MouseEvent, index: number) {
      evt.stopPropagation();
      selectedImageIndex.value = index;
      movingImgIndex.value = index;
      mousePos.x = evt.clientX;
      mousePos.y = evt.clientY;
    }

    function onTouchStartImgItem(evt: TouchEvent, index: number) {
      evt.preventDefault();
      evt.stopPropagation();
      selectedImageIndex.value = index;
      movingImgIndex.value = index;
      mousePos.x = evt.touches[0].clientX;
      mousePos.y = evt.touches[0].clientY;
    }

    function onMouseDown() {
      selectedImageIndex.value = -1;
    }

    function onTouchStart(evt: TouchEvent) {
      evt.preventDefault();
      selectedImageIndex.value = -1;
    }

    function onMouseMove(evt: MouseEvent) {
      if (movingImgIndex.value === -1 &&
        resizingImgIndex.value === -1 &&
        rotatingImgIndex.value === -1 &&
        movingTransformOriginImgIndex.value === -1
      ) return;
      const delta = {x: evt.clientX - mousePos.x, y: evt.clientY - mousePos.y};
      const movement = {
        delta,
        from: {clientX: mousePos.x, clientY: mousePos.y},
        to: {clientX: evt.clientX, clientY: evt.clientY}
      };
      applyPressMove(movement);
      mousePos.x = evt.clientX;
      mousePos.y = evt.clientY;
    }

    function onTouchMove(evt: TouchEvent) {
      if (movingImgIndex.value === -1 &&
        resizingImgIndex.value === -1 &&
        rotatingImgIndex.value === -1 &&
        movingTransformOriginImgIndex.value === -1
      ) return;
      const delta = {x: evt.touches[0].clientX - mousePos.x, y: evt.touches[0].clientY - mousePos.y};
      const movement = {
        delta,
        from: {clientX: mousePos.x, clientY: mousePos.y},
        to: {clientX: evt.touches[0].clientX, clientY: evt.touches[0].clientY}
      };
      applyPressMove(movement);
      mousePos.x = evt.touches[0].clientX;
      mousePos.y = evt.touches[0].clientY;
    }

    function applyPressMove(movement: IMovement2D) {
      if (movingImgIndex.value !== -1) {
        const imgItem = editingPreset.value.images?.[movingImgIndex.value];
        if (!imgItem) return;
        applyImgItemMovement(imgItem, movement);
      } else if (resizingImgIndex.value !== -1) {
        const imgItem = editingPreset.value.images?.[resizingImgIndex.value];
        if (!imgItem) return;
        applyImgItemResize(imgItem, movement);
      } else if (rotatingImgIndex.value !== -1) {
        const imgItem = editingPreset.value.images?.[rotatingImgIndex.value];
        if (!imgItem) return;
        applyImgItemRotate(imgItem, movement);
      } else if (movingTransformOriginImgIndex.value !== -1) {
        const imgItem = editingPreset.value.images?.[movingTransformOriginImgIndex.value];
        if (!imgItem) return;
        applyImgItemTransformOriginMovement(imgItem, movement);
      }
    }

    function applyImgItemMovement(imgItem: IImage, movement: IMovement2D) {
      imgItem.left += movement.delta.x / editorContainerScale.value;
      imgItem.top += movement.delta.y / editorContainerScale.value;
      imgItem.left = Math.round(imgItem.left);
      imgItem.top = Math.round(imgItem.top);
    }

    function applyImgItemResize(imgItem: IImage, movement: IMovement2D) {
      const targetWidth = Math.round(imgItem.width + movement.delta.x / editorContainerScale.value);
      const targetHeight = Math.round(imgItem.height + movement.delta.y / editorContainerScale.value);
      if (targetWidth < 10 || targetHeight < 10) return;
      if (imgItem.equalProportion) {
        let proportion = imgItem.width / imgItem.height;
        imgItem.width = targetWidth;
        imgItem.height = targetWidth / proportion;
      } else {
        imgItem.width = targetWidth;
        imgItem.height = targetHeight;
      }
    }

    function applyImgItemRotate(imgItem: IImage, movement: IMovement2D) {
      if (!editorContainerRect) return;
      const {left: containerLeft, top: containerTop} = editorContainerRect;
      const fromPos = [
        movement.from.clientX - containerLeft,
        movement.from.clientY - containerTop
      ].map(v => v / editorContainerScale.value);
      const toPos = [
        movement.to.clientX - containerLeft,
        movement.to.clientY - containerTop
      ].map(v => v / editorContainerScale.value);
      const center = [
        imgItem.left + imgItem.originX * imgItem.width / 100,
        imgItem.top + imgItem.originY * imgItem.height / 100
      ];
      const v1 = [fromPos[0] - center[0], fromPos[1] - center[1]];
      const v2 = [toPos[0] - center[0], toPos[1] - center[1]];
      const angle = Math.atan2((v1[0] * v2[1] - v2[0] * v1[1]) / (v1[0] * v2[0] + v1[1] * v2[1]), 1) * 180 / Math.PI;
      if (!imgItem.rotation) imgItem.rotation = 0;
      imgItem.rotation += angle;
      imgItem.rotation = Math.round(10 * imgItem.rotation) / 10;
    }

    function applyImgItemTransformOriginMovement(imgItem: IImage, movement: IMovement2D) {
      const deltaX = 100 * movement.delta.x / editorContainerScale.value / imgItem.width;
      const deltaY = 100 * movement.delta.y / editorContainerScale.value / imgItem.height;
      imgItem.originX += deltaX;
      imgItem.originY += deltaY;
      imgItem.originX = Math.round(10 * imgItem.originX) / 10;
      imgItem.originY = Math.round(10 * imgItem.originY) / 10;
    }

    function onMouseUp() {
      movingImgIndex.value = -1;
      resizingImgIndex.value = -1;
      rotatingImgIndex.value = -1;
      movingTransformOriginImgIndex.value = -1;
    }

    function onTouchEnd() {
      movingImgIndex.value = -1;
      resizingImgIndex.value = -1;
      rotatingImgIndex.value = -1;
      movingTransformOriginImgIndex.value = -1;
    }

    function onRemoveImage() {
      if (selectedImageIndex.value !== -1) {
        editingPreset.value.images.splice(selectedImageIndex.value, 1);
        selectedImageIndex.value = -1;
      }
    }

  

    

    return {
      editingPreset,
      selectedImage,
      selectedImageIndex,
      refEditorContainer,
      editorContainerScale,
      getImageUrlFromPath,
      onMouseDownResizer,
      onTouchStartResizer,
      onMouseDownRotateBtn,
      onTouchStartRotateBtn,
      onMouseDownTransformOrigin,
      onTouchStartTransformOrigin,
      onMouseDownImgItem,
      onTouchStartImgItem,
      onMouseDown,
      onMouseMove,
      onMouseUp,
      onTouchStart,
      onTouchMove,
      onTouchEnd,
      onRemoveImage,
    
    };
  }
})
</script>

<style lang="less" scoped>
.editor-container {
  position: absolute;
  top: 20px;
  left: 20px;
  box-shadow: 0 0 20px 2px gray;
  user-select: none;

  .images-container {
    position: relative;
    width: 100%;
    height: 100%;
    overflow: visible;
  }

  .image-container {
    position: absolute;
    font-size: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    transform-origin: 50% 50%;
    box-shadow: 0 0 0 1px lightgray;
    pointer-events: auto;
    cursor: pointer;

    &.selected {
      box-shadow: 0 0 0 2px #52cbfc;
    }

    img {
      width: 100%;
      height: 100%;
      pointer-events: none;
    }

    .rotate-btn {
      position: absolute;
      top: 50%;
    right: 50%;
    transform: translate(50%, -50%);
    width: 50px;
    height: 50px;
    background-image: url(../../resources/images/rotate.png);
      background-repeat: no-repeat;
      background-size: contain;
      background-position: center center;
    }

    .transform-origin {
      position: absolute;
      top: 0;
      left: 0;
      width: 20px;
      height: 20px;
      transform: translate(-10px, -10px);
      border: 2px solid #333;
      background-color: rgba(255, 0, 0, 0.5);
      border-radius: 50%;
      box-sizing: border-box;
      animation: widget-pendulumTriangle-pointBg 2s infinite;
      pointer-events: none;

      &::after {
        content: "";
        position: absolute;
        width: 2px;
        height: 100%;
        top: 0;
        left: calc(50% - 1px);
        background-color: #333;
      }

      &::before {
        content: "";
        position: absolute;
        width: 100%;
        height: 2px;
        top: calc(50% - 1px);
        left: 0;
        background-color: #333;
      }
    }

    .resizer {
      position: absolute;
      width: 20px;
      height: 20px;
      background-color: white;
      border: 1px solid lightgray;
      bottom: -10px;
      right: -10px;
      cursor: nwse-resize;
    }
  }
}

.prop-editor {
  position: absolute;
  top: 0;
  right: 0;
  width: 300px;
  min-height: 100%;
  background-color: #f1f1f1;
  border-left: 1px solid lightgray;
  overflow: visible;

  .prop-item {
    padding: 8px;
   

    .prop-name {
      display: inline-block;
    width: auto;
    padding: 8px;
    /* text-align: right; */
    /* overflow: hidden; */
    vertical-align: middle;
    }

    .prop-value {
      display: inline-block;
    
    }
  }
}
</style>

<style>
@keyframes widget-pendulumTriangle-pointBg {
  0% {
    background-color: rgba(255, 0, 0, 0.5);
  }

  50% {
    background-color: rgba(255, 255, 255, 0.5);
  }

  100% {
    background-color: rgba(255, 0, 0, 0.5);
  }
}
</style>
